package dlt645_v2007_master_connector

import (
	"errors"
	"fmt"
	"github.com/sirupsen/logrus"
	"go-iot-gateway/internal/apk/binarys"
	"go-iot-gateway/internal/channel"
	channel_define "go-iot-gateway/internal/channel/define"
	"go-iot-gateway/internal/conf_table"
	conf_table_define "go-iot-gateway/internal/conf_table/define"
	"go-iot-gateway/internal/storage"
	storage_define "go-iot-gateway/internal/storage/define"
	dlt "go-iot-gateway/pkg/dlt645_2007"
	"strconv"
	"sync"
	"time"
)

type Dlt6452007MasterChannel struct {
	ChannelInfo    channel_define.ChannelInfo
	isClosed       bool
	channelManager *channel.ChannelManager
	handler        *dlt.Client2007Handler
	client         dlt.Client
	lock           sync.Mutex
	readTagList    []*conf_table_define.TagInfo //读点位
	//writeTagList   []*conf_table_define.TagInfo //写点位
	logger       *logrus.Logger
	protocolInfo *RTU2007ProtocolInfo
}

func (d *Dlt6452007MasterChannel) Open() {
	//todo 只做一次

	d.isClosed = false

	d.readTagList = make([]*conf_table_define.TagInfo, 0, 500)
	//d.writeTagList = make([]*conf_table_define.TagInfo, 0, 30)
	tagConfInfos := conf_table.FindAllTagByChlId(d.ChannelInfo.ChlId)

	if len(tagConfInfos) > 0 {
		for _, tag := range tagConfInfos {
			//过滤无效的设备
			if !tag.DeviceInfo.IsValid() {
				continue
			}

			//过滤不是整数地址的
			_, err := strconv.ParseInt(tag.Obj_addr, 10, 32)
			if err != nil {
				continue
			}

			switch tag.Collect_type {
			case 17: //17 读数据
				d.readTagList = append(d.readTagList, tag)
			case 29: //29 读负荷记录
				d.readTagList = append(d.readTagList, tag)
			case 20: //20 读写数据
				d.readTagList = append(d.readTagList, tag)
				//d.writeTagList = append(d.writeTagList, tag)
			case 28: //28 分合闸
				d.readTagList = append(d.readTagList, tag)
				//d.writeTagList = append(d.writeTagList, tag)
			default:
				continue
			}

		}
	}

	go func() { d.connect() }()

	if len(tagConfInfos) <= 0 {
		return
	}

	go func() {
		d.pull()
	}()

	//go func() {
	//	d.healCheck()
	//}()

}

func (d *Dlt6452007MasterChannel) Close() {
	d.isClosed = true
	d.ChannelInfo.SetStatus(channel_define.CONNECT_STATUS_CLOSED, "主动关闭")
	err := d.handler.Close()
	if err != nil {
		d.logger.Warn("通道关闭失败")
	}
}

func (d *Dlt6452007MasterChannel) Info() channel_define.ChannelInfo {
	return d.ChannelInfo
}

func (d *Dlt6452007MasterChannel) connect() {
	if d.ChannelInfo.Status == channel_define.CONNECT_STATUS_CONNECTING || d.ChannelInfo.Status == channel_define.CONNECT_STATUS_CONNECTED {
		return
	}
	d.lock.Lock()
	if d.ChannelInfo.Status == channel_define.CONNECT_STATUS_CONNECTING || d.ChannelInfo.Status == channel_define.CONNECT_STATUS_CONNECTED {
		return
	}
	d.ChannelInfo.SetStatus(channel_define.CONNECT_STATUS_CONNECTING, "连接中")
	d.lock.Unlock()

	for {
		err := d.handler.Connect()
		if err != nil {
			d.logger.Warnf("%s通道连接失败地址： %+v %s", d.ChannelInfo.Name, d.ChannelInfo.ConnectParams, err)
			d.ChannelInfo.SetStatus(channel_define.CONNECT_STATUS_ERROR, "连接错误 "+err.Error())
			time.Sleep(4 * time.Second)
			continue
		}
		d.logger.Debugf("%s通道连接成功  ", d.ChannelInfo.Name)
		//d.clearNumberOfError()
		d.ChannelInfo.SetStatus(channel_define.CONNECT_STATUS_CONNECTED, "连接成功")
		break
	}

}

//func (d *Dlt6452007MasterChannel) reconnect(status channel_define.ConnectStatusType, cause string) {
//	d.ChannelInfo.SetStatus(status, cause)
//	_ = d.handler.Close()
//	d.clearNumberOfError()
//	go func() { d.connect() }()
//}

//func (m *Dlt6452007MasterChannel) increaseNumberOfError() {
//	m.lock.Lock()
//	defer m.lock.Unlock()
//
//	m.numberOfError = m.numberOfError + 1
//}
//
//func (m *Dlt6452007MasterChannel) clearNumberOfError() {
//	m.lock.Lock()
//	defer m.lock.Unlock()
//	//todo 优化使用 原子操作
//	m.numberOfError = 0
//}

//func (d *Dlt6452007MasterChannel) healCheck() {
//	for {
//		maxErrorNum := int64(32)
//		if d.numberOfError >= maxErrorNum {
//			d.reconnect(channel_define.CONNECT_STATUS_ERROR, "错误次数太多") //如果错误达到 32 处理, 就进行重连
//		}
//		time.Sleep(7 * time.Second) //每7 秒执行一次
//	}
//}

func (d *Dlt6452007MasterChannel) pull() {
	//交互频率
	frequency := d.ChannelInfo.Frequency
	//每帧间隔
	waitTime := time.Duration(d.ChannelInfo.WaitTime)

	for !d.isClosed {

		beginTime := time.Now().UnixMilli()

		for _, tagInfo := range d.readTagList {

			if d.isClosed {
				return
			}

			for d.ChannelInfo.Status != channel_define.CONNECT_STATUS_CONNECTED && !d.isClosed {
				time.Sleep(time.Duration(1) * time.Second)
				continue
			}

			d.readData(tagInfo)

			if waitTime > 0 {
				time.Sleep(waitTime * time.Millisecond) //每帧间隔
			}

		}

		//交互频率
		consumeTime := time.Now().UnixMilli() - beginTime
		pauseTime := int64(frequency) - consumeTime
		if pauseTime > 0 && !d.isClosed {
			time.Sleep(time.Duration(pauseTime) * time.Millisecond)
		}

	}

}

func (d *Dlt6452007MasterChannel) readData(tagInfo *conf_table_define.TagInfo) {
	defer func() {
		if rerr := recover(); rerr != nil {
			d.logger.Panicf("[panic] 读取数据失败发现了 panic tagName ", tagInfo.Tag_name, "  error  ", rerr)
		}
	}()

	//todo 批量读
	//todo 要加锁 /dev/ttyS0
	d.handler.SlaveAddr = uint64(tagInfo.DeviceInfo.Dev_comm_addr_int)
	//quantity := dlt645_connector.GetQuantity(tagInfo.ToStrDataType())
	dataMark, err2 := strconv.ParseUint(tagInfo.Obj_addr, 16, 32)
	if err2 != nil {
		d.logger.Error("strconv.ParseUint 失败 tagName: ", tagInfo.Tag_name, " error ", err2)
		return
	}

	var data []byte
	var err error
	for i := 0; i < 1; i++ { //todo 重试次数配置
		data, err = d.client.ReadData(uint32(dataMark), 0, 0, 0, 0, 0, 0)
		if err == nil {
			break
		}
	}

	if err != nil {
		d.logger.Error("读取数据失败 tagName ", tagInfo.Tag_name, " error  ", err)
		//d.increaseNumberOfError() //添加错误次数
		return
	}

	//d.clearNumberOfError()

	//61 02 00 00
	valObject := storage_define.NewValObject(tagInfo)
	data = binarys.RankBytes1234(data, "4321")
	intVal, err := parseBytes(data)
	if err != nil {
		d.logger.Error("创建 ParseInt 失败 ", data, " error ", err)
		valObject = storage_define.NewNilVal(tagInfo).SetQos(storage_define.QOS_BAD)
	} else {
		_ = valObject.SetVal(intVal)
	}

	//err = valObject.SetBytes(data, tagInfo.ToStrDataFormat())
	//if err != nil {
	//	logger.Connector().Error("创建 ValObject 失败", err)
	//	valObject = storage_define.NewNilVal(tagInfo).SetQos(storage_define.QOS_BAD)
	//}

	storage.SaveAndNotify(valObject)
}

func parseBytes(b []byte) (int64, error) {
	if b == nil {
		return 0, errors.New("值为空")
	}

	bLen := len(b)
	if bLen <= 0 {
		return 0, nil
	}

	str := ""
	for i := 0; i < bLen; i++ {
		if b[i] == 0 {
			continue
		}
		str = str + fmt.Sprintf("%x", b[i])
	}
	if str == "" {
		return 0, nil
	}
	return strconv.ParseInt(str, 10, 64)
}
